import subprocess
import rrd_base
import re
import time
import os

import snmp
import color

try:
    from pyrrd.rrd import DataSource, RRA, RRD
    from pyrrd.graph import DEF, CDEF, VDEF
    from pyrrd.graph import LINE, AREA, GPRINT, PRINT
    from pyrrd.graph import ColorAttributes, Graph
except:
    print "Couldn't load required modules. You probably need to install it with:"
    sys.exit('sudo apt-get install python-pyrrd python-pysnmp4')

class RrdCpuTemp(rrd_base.RrdBase):
    def __init__(self, domain, name):
        super(RrdCpuTemp,self).__init__(domain=domain, group="cpu", instance="temperature_{0}".format(name))

    def create_file(self):
        dataSources = []
        dataSources.append(DataSource( dsName='temperature', dsType='GAUGE', heartbeat=self.heartbeat()))
        dataSources.append(DataSource( dsName='limit',       dsType='GAUGE', heartbeat=self.heartbeat()))

        roundRobinArchives = []
        for func in ['AVERAGE', 'MAX', 'MIN']:
            for step,row in self.rra_pattern():
                roundRobinArchives.append(RRA(cf=func, xff=0.5, steps=step, rows=row))

        self.myRRD = RRD(self.filename, ds=dataSources, rra=roundRobinArchives, step=self.data_step())
        self.myRRD.create()

    def graph(self):
        d_temp_avg   =  DEF(rrdfile=self.myRRD.filename, vname='d0', dsName='temperature', cdef="AVERAGE")
        d_temp_max   =  DEF(rrdfile=self.myRRD.filename, vname='d1', dsName='temperature', cdef="MAX")
        d_temp_min   =  DEF(rrdfile=self.myRRD.filename, vname='d2', dsName='temperature', cdef="MIN")
        d_lim_avg    =  DEF(rrdfile=self.myRRD.filename, vname='d3', dsName='limit',       cdef="AVERAGE")
        v_temp_peak  = VDEF(vname="v0", rpn="{0},MAXIMUM".format(d_temp_max.vname))
        v_temp_nadir = VDEF(vname="v1", rpn="{0},MINIMUM".format(d_temp_min.vname))
        v_temp_avg   = VDEF(vname="v2", rpn="{0},AVERAGE".format(d_temp_avg.vname))
        a       = AREA(   defObj=d_temp_avg,   color=color.RGBA['green'])
        l_max   = LINE(1, defObj=d_temp_max,   color=color.RGBA['red'],        legend="Max")
        l_min   = LINE(1, defObj=d_temp_min,   color=color.RGBA['blue'],       legend="Min")
        l_peak  = LINE(1, defObj=v_temp_peak,  color=color.RGBA['red'],        legend="Peak")
        l_nadir = LINE(1, defObj=v_temp_nadir, color=color.RGBA['blue'],       legend="Nadir")
        l_avg   = LINE(1, defObj=v_temp_avg,   color=color.RGBA['green'],      legend="Avg")
        l_limit = LINE(1, defObj=d_lim_avg,    color=color.RGBA['darkorange'], legend="Limit")
        p_peak  = GPRINT(v_temp_peak,  "(%.1lf%sC)")
        p_nadir = GPRINT(v_temp_nadir, "(%.1lf%sC)")
        p_avg   = GPRINT(v_temp_avg,   "(%.1lf%sC)")

        for tf in self.graph_time_frames().keys():
            g = Graph(self.image_name(tf),
                      start=int(time.time())-self.graph_time_frames()[tf], end=int(time.time()),
                      lower_limit=0.000001,
                      title='"Core Temperature for {0} - Updated {1}"'.format(self.data_domain, time.strftime("%Y%m%d at %H:%M")),
                      vertical_label='"Degrees C"',
                      height=self.graph_height, width=self.graph_width,
                      x_grid=self.grid[tf],
                      step=self.graph_step_times[tf])
            g.data.extend([d_temp_avg, d_temp_max, d_temp_min, d_lim_avg, v_temp_peak, v_temp_nadir, v_temp_avg, a, l_limit])
            if self.graph_time_frames()[tf] > self.graph_time_frames()["1month"]:
                g.data.extend([l_max, l_min])
            g.data.extend([l_peak, p_peak, l_nadir, p_nadir, l_avg, p_avg])
            g.write()

class RrdCpuTempSys(RrdCpuTemp):
    def __init__(self, domain, sensor_file, limit, name):
        super(RrdCpuTempSys,self).__init__(domain=domain, name=name)
        self.sensor_file = sensor_file
        self.sensor_limit = limit

    def update(self):
        if False == os.path.isfile(self.sensor_file):
            return

        f = open(self.sensor_file)
        for line in f:
            val = float(line)/1000.0
            if val < 200.0 and val > -200.0:
                self.myRRD.bufferValue(int(round(time.time())), val, self.sensor_limit)
                self.myRRD.update()
                return

class RrdCpuTempLmSensors(RrdCpuTemp):
    def __init__(self, domain, sensor_name):
        super(RrdCpuTempLmSensors,self).__init__(domain=domain, name=sensor_name)
        self.sensor_name = sensor_name

    def update(self):
        lines = subprocess.Popen(["/usr/bin/sensors", "-u"], shell=False, stdout=subprocess.PIPE)
        found_temp = False
        found_max  = False
        for line in lines.communicate()[0].split("\n"):
            if re.match("  {0}_input: ".format(self.sensor_name), line):
                key, temp = line.split()
                found_temp = True
            if re.match("  {0}_max: ".format(self.sensor_name), line):
                key, maximum = line.split()
                found_max = True

            if found_temp and found_max:
                self.myRRD.bufferValue(int(round(time.time())), float(temp), float(maximum))
                self.myRRD.update()
                return
